package com.lubase.metadata.service.impl;

import com.alibaba.fastjson.JSON;
import com.lubase.metadata.model.ColumnMetaModel;
import com.lubase.metadata.model.ConstraintMetaModel;
import com.lubase.metadata.model.ELakeStatus;
import com.lubase.metadata.model.TableMetaModel;
import com.lubase.metadata.service.MetadataProcessService;
import com.lubase.metadata.service.MetadataReadService;
import com.lubase.metadata.service.ZhPercentageService;
import com.lubase.metadata.util.ZhChineseUtil;
import com.lubase.model.DbEntity;
import com.lubase.model.EDBEntityState;
import com.lubase.orm.QueryOption;
import com.lubase.orm.TableFilter;
import com.lubase.orm.exception.WarnCommonException;
import com.lubase.model.DbCollection;
import com.lubase.orm.service.AppHolderService;
import com.lubase.orm.service.DataAccess;
import com.lubase.orm.util.TableFilterWrapper;
import com.lubase.orm.util.TypeConverterUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class MetadataProcessServiceImpl implements MetadataProcessService {

    @Autowired
    MetadataReadService metadataReadService;

    @Autowired
    DataAccess dataAccess;
    @Autowired
    ZhPercentageService zhPercentageService;
    @Autowired
    AppHolderService appHolderService;

    @SneakyThrows
    @Override
    public Integer processMetadataByDatabaseId(String databaseId) {
        // 检查参数是否为空
        if (databaseId == null || databaseId.isEmpty()) {
            log.error("processMetadataByDatabaseId: databaseId is empty");
            return 0;
        }
        DbCollection collDatabase = getSystemIdByDatabaseId(databaseId);
        String systemId = collDatabase.getData().get(0).get("ms_system_list_id").toString();
        String dbManager = TypeConverterUtils.object2String(collDatabase.getData().get(0).get("db_manager"), "");
        if (StringUtils.isEmpty(dbManager)) {
            throw new WarnCommonException("您无权限维护此数据源");
        }
        if (!dbManager.contains(appHolderService.getUser().getCode())) {
            throw new WarnCommonException("您无权限维护此数据源");
        }


        Boolean process = true;
        try {
            List<TableMetaModel> tableList = metadataReadService.getTableList(databaseId);
            DbCollection collTable = processTable(tableList, databaseId, systemId);
            processColumn(databaseId, systemId, collTable);
            processConstraint(databaseId, systemId);
            collDatabase.getData().get(0).put("last_update", LocalDateTime.now());
            collDatabase.getData().get(0).put("last_msg", "读取成功");
            collDatabase.getData().get(0).put("table_count", tableList.size());
        } catch (Exception e) {
            log.error("processMetadataByDatabaseId: ", e);
            collDatabase.getData().get(0).put("last_update", LocalDateTime.now());
            String msg = e.getMessage();
            if (msg.length() > 256) {
                msg = msg.substring(0, 256);
            }
            collDatabase.getData().get(0).put("last_msg", msg);
            process = false;
        }
        dataAccess.update(collDatabase);
        // 计算中文占比
        if (process) {
            zhPercentageService.calculateZhPercentageOfAllTable(databaseId);
        }
        return process ? 1 : 0;
    }

    DbCollection processTable(List<TableMetaModel> tableList, String databaseId, String systemId) {
        // 合并两个数据库
        DbCollection collTable = getExistsTableList(databaseId);
        collTable.getData().parallelStream().forEach(entity -> {
            TableMetaModel existsMeta = tableList.stream().filter(t -> t.getTableName().equals(entity.get("table_code"))).findFirst().orElse(null);
            entity.setState(EDBEntityState.Modified);
            if (existsMeta != null) {
                // 从元数据库更新
                entity.put("table_name", existsMeta.getTableComment());
                // 修改字段如果手工维护为空，且包含中文注释则存到merge_name字段
                String aliasName = TypeConverterUtils.object2String(entity.get("alias_name"), "");
                if ((StringUtils.isEmpty(aliasName) || aliasName.equals(existsMeta.getTableName())) && ZhChineseUtil.containsChinese(existsMeta.getTableComment())) {
                    entity.put("merge_name", existsMeta.getTableComment());
                }
            } else {
                entity.put("delete_tag", 1);
            }
        });
        tableList.forEach(meta -> {
            DbEntity existsEntity = collTable.getData().stream().filter(entity -> entity.get("table_code").equals(meta.getTableName())).findFirst().orElse(null);
            if (existsEntity == null) {
                DbEntity entity = collTable.newEntity();
                entity.setState(EDBEntityState.Added);
                entity.put("table_code", meta.getTableName());
                entity.put("table_name", meta.getTableComment());
                // 新增字段如果包含中文注释则存到merge_name字段
                if (ZhChineseUtil.containsChinese(meta.getTableComment())) {
                    entity.put("merge_name", meta.getTableComment());
                }
                entity.put("ms_database_id", databaseId);
                entity.put("ms_system_list_id", systemId);
                entity.put("delete_tag", 0);
                entity.put("model_type", 1);
                entity.put("lake_status", ELakeStatus.NotLake.getType());// 入湖状态0 未入湖
                collTable.getData().add(entity);
            }
        });
        collTable.setEnableTableTrigger(false);
        dataAccess.update(collTable);
        return collTable;
    }

    void processConstraint(String databaseId, String systemId) {
        List<ConstraintMetaModel> constraintList = metadataReadService.getTableConstraintList(databaseId);
        DbCollection collConstraint = getExistsConstraintList(databaseId);
        collConstraint.getData().parallelStream().forEach(entity -> {
            entity.setState(EDBEntityState.Deleted);
        });
        constraintList.forEach(meta -> {
            DbEntity entity = collConstraint.newEntity();
            entity.setState(EDBEntityState.Added);
            entity.put("table_code", meta.getTableName());
            entity.put("column_code", meta.getColumnName());
            entity.put("constraint_name", meta.getConstraintName());
            entity.put("constraint_type", meta.getConstraintType());
            entity.put("ref_table_code", meta.getReferencedTableName());
            entity.put("ref_column_code", meta.getReferencedColumnName());
            entity.put("from_database", meta.getIsFromDatabase() ? 1 : 0);
            entity.put("ms_database_id", databaseId);
            entity.put("ms_system_list_id", systemId);
            collConstraint.getData().add(entity);
        });
        collConstraint.setEnableTableTrigger(false);
        dataAccess.update(collConstraint);
    }

    void processColumn(String databaseId, String systemId, DbCollection collTable) {
        List<ColumnMetaModel> columnList = metadataReadService.getTableColumnList(databaseId);
        DbCollection collColumn = getExistsColumnList(databaseId);
        collColumn.getData().parallelStream().forEach(entity -> {
            ColumnMetaModel existsMeta = columnList.stream().filter(t -> t.getTableName().equals(entity.get("table_code")) && t.getColumnName().equals(entity.get("column_code"))).findFirst().orElse(null);
            if (existsMeta != null) {
                // 从元数据库更新
                entity.setState(EDBEntityState.Modified);
                entity.put("column_name", existsMeta.getColumnComment());
                entity.put("column_type", existsMeta.getColumnType());
                // 修改字段如果手工维护为空，且包含中文注释则存到merge_name字段
                String aliasName = TypeConverterUtils.object2String(entity.get("alias_name"), "");
                if ((StringUtils.isEmpty(aliasName) || aliasName.equals(existsMeta.getColumnName())) && ZhChineseUtil.containsChinese(existsMeta.getColumnComment())) {
                    entity.put("merge_name", existsMeta.getColumnComment());
                }
            } else {
                entity.setState(EDBEntityState.Deleted);
            }
        });
        columnList.forEach(meta -> {
            DbEntity existsEntity = collColumn.getData().stream().filter(entity -> entity.get("table_code").equals(meta.getTableName()) && entity.get("column_code").equals(meta.getColumnName())).findFirst().orElse(null);
            if (existsEntity == null) {
                DbEntity entity = collColumn.newEntity();
                entity.setState(EDBEntityState.Added);
                entity.put("table_code", meta.getTableName());
                entity.put("column_code", meta.getColumnName());
                entity.put("column_name", meta.getColumnComment());
                // 新增字段如果包含中文注释则存到merge_name字段
                if (ZhChineseUtil.containsChinese(meta.getColumnComment())) {
                    entity.put("merge_name", meta.getColumnComment());
                }
                entity.put("column_type", meta.getColumnType());
                entity.put("codedata_tag", 0);

                entity.put("ms_database_id", databaseId);
                entity.put("ms_system_list_id", systemId);
                DbEntity tmpEntity = collTable.getData().stream().filter(table -> table.get("table_code").equals(meta.getTableName())).findFirst().orElse(null);
                if (tmpEntity == null) {
                    System.out.println("1111111111111" + JSON.toJSONString(meta));
                }
                else {
                    String tableId = tmpEntity.get("id").toString();
                    entity.put("mt_table_id", tableId);
                    collColumn.getData().add(entity);
                }
            }
        });
        collColumn.setEnableTableTrigger(false);
        dataAccess.update(collColumn);
    }


    DbCollection getExistsTableList(String databaseId) {
        QueryOption queryOption = new QueryOption("mt_table");
        queryOption.setTableFilter(new TableFilter("ms_database_id", databaseId));
        return dataAccess.queryAllData(queryOption);
    }

    DbCollection getExistsColumnList(String databaseId) {
        QueryOption queryOption = new QueryOption("mt_column");
        queryOption.setTableFilter(new TableFilter("ms_database_id", databaseId));
        return dataAccess.queryAllData(queryOption);
    }

    DbCollection getExistsConstraintList(String databaseId) {
        QueryOption queryOption = new QueryOption("mt_constraint");
        TableFilterWrapper filterWrapper = TableFilterWrapper.and();
        filterWrapper.eq("ms_database_id", databaseId).eq("from_database", 1);
        queryOption.setTableFilter(filterWrapper.build());
        return dataAccess.queryAllData(queryOption);
    }

    @SneakyThrows
    DbCollection getSystemIdByDatabaseId(String databaseId) {
        DbCollection coll = dataAccess.queryById("ms_database", Long.parseLong(databaseId));
        if (coll.getData().isEmpty()) {
            throw new WarnCommonException("databaseId not found");
        } else {
            return coll;
        }
    }

}
